# -*- coding: utf-8 -*-
"""
Created on Thu Dec 15 15:45:58 2011

@author: Timothy.Wiseman
"""

aboutText = """
PicTwister
Version 0.2 19 DEC 11
Author: TimothyAWiseman@gmail.com

Changes:
    Removed alternate and both from the gui options.  Results just don't look good
    Add multiprocessing to take advantage of multiple processors when available.
    Broke it up to preload the files and then keep reusing them as they shrink.
        This helps reduce the IO (though it does end up capping the total number of pics used).
        slightly more complicated than it should be due to PIL trying to deal with files being
            closed in other threads.  

This simple program will take a series 
of images and generate one image composed
of a randomized array of these pictures 
based on the parameters supplied.

It was written to make a Christmas 
present for my wife, Renee, using pictures
of the Children and is dedicated to her."""

###############################################################################
#imports

#Gui imports
import sys #needed by Qt
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt #for simplicity in calling
from PicSpiralUi import Ui_MainWindow

#working imports
#import PicSpiralCore as ps
import PicSpiralCore as ps
import ImageQt
from time import sleep

#imports needed for py2exe, actually used in other modules
import os
from PIL import Image
from collections import namedtuple
from random import seed, choice
import sip
import multiprocessing

###############################################################################
#Classes

class PSMainWin(QtGui.QMainWindow):
    
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        
        #connecting signals and slots
        QtCore.QObject.connect(self.ui.selectPicBtn, QtCore.SIGNAL("clicked()"),
                               self.selectPics)
        QtCore.QObject.connect(self.ui.selectPicFolderBtn,
                               QtCore.SIGNAL("clicked()"),
                                self.selectFolder)
        QtCore.QObject.connect(self.ui.resetListBtn,
                               QtCore.SIGNAL("clicked()"),
                                self.resetFileList)
        QtCore.QObject.connect(self.ui.outputFnBtn,
                               QtCore.SIGNAL("clicked()"),
                                self.selectOutputFile)
        QtCore.QObject.connect(self.ui.outFnLine,
                               QtCore.SIGNAL("clicked()"),
                                self.selectOutputFile)
        QtCore.QObject.connect(self.ui.genPicBtn,
                               QtCore.SIGNAL("clicked()"),
                                self.genPicture)
        QtCore.QObject.connect(self.ui.actionAbout,
                               QtCore.SIGNAL("triggered()"),
                                self.dispHelpText)
                                
        #enable drag and drop
        self.ui.fileListPTE.dragEnterEvent = self.PTE_dragEnterEvent
        self.ui.fileListPTE.dropEvent = self.PTE_dropEvent
        self.ui.fileListPTE.dragMoveEvent = self.PTE_dragMoveEvent
        
    def dispHelpText(self):
        QtGui.QMessageBox.information(self, 'About', aboutText)
        
    def selectPics(self):
        fns = QtGui.QFileDialog.getOpenFileNames(self)
        newText = self.ui.fileListPTE.toPlainText()
        if len(newText) >= 1 and not newText[-1] == '\n':
            newText += '\n'
        for path in fns:
            newText = newText +  path +'\n'
        self.ui.fileListPTE.setPlainText(newText)
        
    def selectFolder(self):
        folderName = QtGui.QFileDialog.getExistingDirectory(self)
        newText = self.ui.fileListPTE.toPlainText() + '\n' + folderName
        self.ui.fileListPTE.setPlainText(newText)
        
    def resetFileList(self):
        self.ui.fileListPTE.setPlainText('')
        
    def selectOutputFile(self):
        fn = QtGui.QFileDialog.getSaveFileName(self, filter='*.jpg')
        self.ui.outFnLine.setText(fn)     
        
    #functions to implement the drag and drop
    #works right now, but does not accept files or directories so needs serious work.        
    def PTE_dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()
            
    def PTE_dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def PTE_dropEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            
            newText = self.ui.fileListPTE.toPlainText()
            for url in event.mimeData().urls():
                newText += '\n' + str(url.toLocalFile())
            self.ui.fileListPTE.setPlainText(newText)
            self.emit(QtCore.SIGNAL("dropped"))
        else:
            event.ignore()

        
    def genPicture(self):
        """runs the program to actually generate the twisted picture."""
        #Get the list of files
        fileList = ps.procFileStr(fileStr = self.ui.fileListPTE.toPlainText(), 
                    extension = 'jpg', strict = False)
        if len(fileList) == 0:
            QtGui.QMessageBox.information(self,
                                          'information',
                                          'No jpg files selected.')
            return
        if not str(self.ui.outFnLine.text()).endswith('.jpg'):
            QtGui.QMessageBox.information(self,
                                          'information',
                                          'Incorrect output file name.')
            return
        mainSizeStr = str(self.ui.mainSizeBox.currentText())
        try:
            mainSize = (
                int(mainSizeStr[:mainSizeStr.index('x')]),
                int(mainSizeStr[mainSizeStr.index('x')+1:])
                )
        except:
            QtGui.QMessageBox.information(self,
                                          "information",
                                          'The screen size was not properly' + 
                                          'formatted.  Please use ####x####' +
                                          'format. \n  Error: {0}\n {1}'.format(
                                          sys.exc_info()[0], sys.exc_info()[1])
                                          )    
            return
        try:
            frac = float(self.ui.fracBox.currentText())/100.0
            offset = float(self.ui.offsetBox.currentText())/100.0
            border =  int(self.ui.borderBox.currentText())  
        except:   
            QtGui.QMessageBox.information(self,
                                          "information",
                                          'The Percent, Offset, or Border ' +
                                          'Cannot be processed.  Please use a '+
                                          'number' +
                                          '\n  Error: {0}\n {1}'.format(
                                          sys.exc_info()[0], sys.exc_info()[1])
                                          ) 
            return
            
            
        try:
            QtGui.QApplication.setOverrideCursor(QtGui.QCursor(Qt.WaitCursor))
            imgGen = ps.yieldPicSpiral(picFileNames = fileList, 
                               mainSize = mainSize, 
                                 rotate = str(self.ui.rotateBox.currentText()), 
                                 frac = frac, offset = offset, border = border,
                                 sizing = str(self.ui.resizingBox.currentText())
                                 )

            self.ui.progressBar.setEnabled(True)      
            self.ui.progressBar.setMinimum(0)
            self.ui.progressBar.setMaximum(10)
            prog = 0
            
            scene = QtGui.QGraphicsScene()
            self.ui.previewGv.setScene(scene)
            
            #This was meant to show a preview at each step, but I had
            #problems with the program locking up after it lost focus
            #that way.  For now, just reloading the image that was just
            #saved seems to resolve that problem.
            #I'm leaving many of the old lines in and commented out 
            #because I intend to eventually return to this and
            #get it to display the preview at each step.
            
            for img in imgGen:       
                QtGui.QApplication.processEvents()
                #Display the preview.
                #imgQ = ImageQt.ImageQt(img)
                #pixMap = QtGui.QPixmap.fromImage(imgQ)
                prog += 1
                self.ui.progressBar.setValue(prog)
                #scene.clear()
                #scene.addPixmap(pixMap) 
                #self.ui.previewGv.fitInView(QtCore.QRectF(0, 0, mainSize[0], mainSize[1]) ,
                #                                Qt.KeepAspectRatio)
                #self.ui.previewGv.repaint()
                #self.ui.previewGv.show()
                QtCore.QCoreApplication.processEvents()                         

            #imgQ = ImageQt.ImageQt(img)
            #pixMap = QtGui.QPixmap.fromImage(imgQ)

            img.save(str(self.ui.outFnLine.text()))
            
            thePixmap = QtGui.QPixmap(QtGui.QImage(self.ui.outFnLine.text()))
            scene.clear()
            scene.addPixmap(thePixmap) 
            self.ui.previewGv.fitInView(QtCore.QRectF(0, 0, mainSize[0], mainSize[1]) ,
                                            Qt.KeepAspectRatio)
            self.ui.previewGv.repaint()
            self.ui.previewGv.show()
            QtCore.QCoreApplication.processEvents()              
            
            
            
            
            #pixMap = pixMap.scaled(self.ui.previewGv.size())
            #scene.clear()
                          
            img.save(str(self.ui.outFnLine.text()))
            self.ui.progressBar.setValue(10)    
            QtGui.QApplication.restoreOverrideCursor()
            QtGui.QMessageBox.information(self,
                                          "information",
                                          'File {} created.'.format(
                                          self.ui.outFnLine.text())
                                          )  
            QtCore.QCoreApplication.processEvents() 
            
            #This proved more annoying than useful, so commenting it out.
            #self.resetFileList()

            self.ui.progressBar.setValue(0)
            self.ui.progressBar.setEnabled(False)

            
        except:
            QtGui.QMessageBox.information(self,
                                          "information",
                                          '\n  Error: {0}\n {1}'.format(
                                          sys.exc_info()[0], 
                                          sys.exc_info()[1])
                                          )  
            raise
        finally:
            #make sure this happens even if there was an error
            QtGui.QApplication.restoreOverrideCursor()
            
        return
                    
        
##############################################################################
#Functions


###############################################################################
#Mainloop
        
if __name__ == "__main__":
    multiprocessing.freeze_support()
    app = QtGui.QApplication(sys.argv)
    appGui = PSMainWin()
    appGui.show()
    sys.exit(app.exec_())
    
    